﻿package net.sealuitk.gadgets 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import net.sealuitk.Gadget;
	import net.sealuitk.UIConst;
	import net.sealuitk.Util;
	
	/**
	 * ...
	 * @author mkn
	 */
	public class Button extends Gadget
	{
		public var state:String = UIConst.STATE_UP;
		private var _graphicsMode:String;
		
		protected var bSprite:Array = new Array(5);
		protected var bFunction:Vector.<Function> = new Vector.<Function>(5);
		
		protected var states:Array = UIConst.statesArray;
		
		/* ================ Constructor ================
		 * 
		 */
		
		/** New Button Gadget
		 * 
		 * @param	Name
		 */
		public function Button(Name:String, GraphicsMode:String = UIConst.GRAPHICS_FIXED) {
			super(Name);
			if (GraphicsMode != null) graphicsMode = GraphicsMode;
				else graphicsMode = UIConst.GRAPHICS_FIXED
		}
		
		/* ================ Inits ================
		 * 
		 */
		
		/** Assign graphics and function for a button State
		 * 
		 * @param	toState			State to be addressed
		 * @param	newGraphics		State Graphics
		 * @param	newFunction		State Function
		 */
		public function assign(toState:String, newGraphics:*, newFunction:Function):void {
			assignGraphics(toState, newGraphics);
			assignFunction(toState, newFunction);
		}
		
		/**	Assign graphics for a button State
		 * 
		 * @param	toState			State
		 * @param	newGraphics		Graphics
		 */
		public function assignGraphics(toState:String, newGraphics:*):void {
			var targetState:int = stateInt(toState);
			
			if (newGraphics is Bitmap) newGraphics = new Bitmap(newGraphics.bitmapData);
			else if (newGraphics is BitmapData) newGraphics = new Bitmap(newGraphics);
			else if (newGraphics is Sprite == false) throw Error("Button graphics must be type Bitmap, BitmapData or Sprite");
			
			bSprite[ targetState ] = newGraphics;
			addChild( bSprite[ targetState ] );
			
			if (sizeSet == false) {
				size.x = Math.max(size.x, newGraphics.width);
				size.y = Math.max(size.y, newGraphics.height);
			}
			
			setGraphics(state);
			updateGraphics();
		}
		
		/**	Assign a function to be called for a State 
		 * 
		 * @param	toState
		 * @param	newFunction
		 */
		public function assignFunction(toState:String, newFunction:Function):void {
			bFunction[ stateInt(toState) ] = newFunction;
		}
		
		/** Flush graphics from Button, dispose bitmapData properly.
		 * 
		 */
		public function disposeGraphics():void {
			for (var s:int = 0; s < states.length; s++) {
				if (bSprite[s] != null && bSprite[s] is Bitmap) {
					bSprite[s].bitmapData.dispose();
				}
				bSprite[s] == null;
			}
		}
		
		/* ================ Functions ================
		 * 
		 */
		
		/** Rescales button according to buttonMode
		 * 
		 */
		protected function updateGraphics():void {
			for (var s:int = 0; s < states.length ; s++) {
				if(bSprite[s] != null){
					switch(graphicsMode) {
						case UIConst.GRAPHICS_FIXED:
							bSprite[s].scaleX = 1;
							bSprite[s].scaleY = 1;
							bSprite[s].x = 0;
							bSprite[s].y = 0;
						break;
						case UIConst.GRAPHICS_CENTER:
							bSprite[s].scaleX = 1;
							bSprite[s].scaleY = 1;
							bSprite[s].x = (width - bSprite[s].width) / 2;
							bSprite[s].y = (height - bSprite[s].height) / 2;
						break;
						case UIConst.GRAPHICS_STRETCH:
							bSprite[s].width = width;
							bSprite[s].height = height;
							bSprite[s].x = 0;
							bSprite[s].y = 0;
						break;
						default:
							throw Error("Unknown mode:" + graphicsMode);
						break;
					}
				}
			}
			update();
		}
		
		/** Change button state
		 * 
		 * @param	newState
		 */
		public function setTo(newState:String, SetGraphics:Boolean = true, CallFunction:Boolean = true):void {
			if (SetGraphics) setGraphics(newState);
			if (CallFunction) callFunction(newState);
			state = newState;
		}
		
		/**	Call function if valid
		 * 
		 * @param	thisFunction
		 */
		protected function callFunction(ofState:String):Boolean {
			var targetState:int = stateInt(ofState);
			if (bFunction[targetState] != null) {
				bFunction[targetState].call();
				return true;
			} else return false;
		}
		
		/** Switch to state Sprite if valid
		 * 
		 */
		protected function setGraphics(toState:String):Boolean {
			var targetState:int = stateInt(toState);
			// If toState is valid and bSprite exists
			if (bSprite[targetState] != null) {
				// Cycle through state sprites
				for (var s:int = 0; s < states.length ; s++) {
					// If state sprite exist, turn it off
					if(bSprite[s] != null) bSprite[s].visible = false;
				}
				// Turn toState sprite on
				bSprite[targetState].visible = true;
				return true;
			} else return false;
			updateGraphics();
		}
		
		/* ================ Event Listener ================
		 * 
		 */
		
		protected function buildEventListener():void {
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
			addEventListener(MouseEvent.ROLL_OVER, mouseOver);
			addEventListener(MouseEvent.ROLL_OUT, mouseOut);
		}
		
		protected function mouseDown(e:MouseEvent):void {
			if (state == UIConst.STATE_UP || state == UIConst.STATE_OVER) setTo(UIConst.STATE_DOWN);
			else if (state == UIConst.STATE_DOWN || state == UIConst.STATE_DOWNOVER) setTo(UIConst.STATE_UP);
		}
		
		protected function mouseOver(e:MouseEvent):void {
			if (state == UIConst.STATE_UP) {
				setTo(UIConst.STATE_OVER);
			} else if (state == UIConst.STATE_DOWN) {
				setTo(UIConst.STATE_DOWNOVER);
			}
		}
		
		protected function mouseOut(e:MouseEvent):void {
			if (state == UIConst.STATE_OVER) {
				setTo(UIConst.STATE_UP, true, false);
			} else if (state == UIConst.STATE_DOWNOVER) {
				setTo(UIConst.STATE_DOWN, true, false);
			}
		}
		
		/* ================ MISC ================
		 * 
		 */
		
		/** Return integer of input string from states array
		 * 
		 * @param	string
		 * @return	int
		 */
		protected function stateInt(string:String):int {
			if ( states.indexOf(string) > -1 ) return states.indexOf(string);
			else throw Error("Unknown state: " + string);
		}
		
		/**	Set button size
		 * 
		 * @param	Width
		 * @param	Height
		 * @param	SizeSet	Button has a fixed size
		 */
		override public function setSize(Width:Number, Height:Number, SizeSet:Boolean = true):void {
			super.setSize(Width, Height, SizeSet);
			updateGraphics();
			updateParentContainer();
		}
		
		/* ================ Getters & Setters ================
		 * 
		 */
		
		public function set graphicsMode(newMode:String):void {
			_graphicsMode = newMode;
			updateGraphics();
		}
		
		public function get graphicsMode():String { return _graphicsMode; }
		
	}
}